#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include <vector>
#include <map>
#include "DxEnum.h"
#include "defs.h"
#include "../../D3D/D3D/dlgTemplate.h"
#include "../../D3D/D3D/msgproc.h"
#include "Gets.h"
#include "font.h"
using namespace std;

#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")

const float INTERVAL = 0.01f;
const int DEFAULTCLIENTWIDTH = 800;
const int DEFAULTCLIENTHEIGHT = 600;
const int FPSRECTWIDTH = 200;
const int FPSRECTHEIGHT = 200;

#define GET_ACCESSOR(x,y) x Get##y(){ return m_D3DState.m_##y; };
#define SET_ACCESSOR(x,y) void Set##y(x t){ m_D3DState.m_##y = t; };
#define GET_SET_ACCESSOR(x,y) GET_ACCESSOR(x,y) SET_ACCESSOR(x,y)

#define GETP_ACCESSOR(x,y) x* Get##y(){ return &(m_D3DState.m_##y); };
#define SETP_ACCESSOR(x,y) void Set##y(x* t){ m_D3DState.m_##y = *t; };
#define GETP_SETP_ACCESSOR(x,y) GETP_ACCESSOR(x,y) SETP_ACCESSOR(x,y)

LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);

//drawing method
typedef void (CALLBACK* fpOnInit)();
typedef HRESULT (CALLBACK* fpRender)();
typedef bool (CALLBACK* fpOnLostDevice)();
typedef bool (CALLBACK* fpOnResetDevice)();
typedef void (CALLBACK* fpUpdate)(float fElapsedTime);
typedef void (CALLBACK* fpRelease)();


class cTimeCounter
{
public:
	cTimeCounter():preCount(0),aftCount(0),
		cntsPersec(0),secsPercnt(0.0f),elapsedTime(0.0f),FPS(0.0f){
	}
	void QueryPreCount();
	void QueryAftCount();	
	float GetElapsedTime(){ return elapsedTime; }
	float GetFPS(){ return FPS; }
private:
	__int64 preCount;
	__int64 aftCount;
	__int64 cntsPersec;
	float secsPercnt;
	float elapsedTime;
	float FPS;
};

struct cD3DDeviceSettings
{
	UINT m_nAdapterOrdinal;
	D3DDEVTYPE m_DeviceType;
	D3DFORMAT m_AdapterFmt;
	DWORD m_dwBehaviorFlags;

	D3DPRESENT_PARAMETERS m_D3DPP;
};


class cD3DFrame
{
public:
	cD3DFrame(){
		m_TimeCounter = new cTimeCounter;
	}
	struct cD3D{
		cD3D();
		cD3DDeviceSettings m_D3DDeviceSettings;
		D3DCAPS9 m_D3DCaps9;
		D3DSURFACE_DESC m_D3DBackBufferSurface;

		LPDIRECT3DDEVICE9 m_D3DDEVICE9;
		LPDIRECT3D9 m_D3D9;

		HWND m_HWND;
		HWND m_DlgHWND;
		HWND m_FocusHWND;
		bool m_WindowedState;
		float m_FPS;
		bool m_Display;
		WCHAR m_WindowTitle[256];
	};
	GET_SET_ACCESSOR(LPDIRECT3D9,D3D9);
	GET_SET_ACCESSOR(LPDIRECT3DDEVICE9,D3DDEVICE9);
	GETP_SETP_ACCESSOR(D3DCAPS9,D3DCaps9);
	GETP_SETP_ACCESSOR(cD3DDeviceSettings,D3DDeviceSettings);
	GETP_SETP_ACCESSOR(D3DSURFACE_DESC,D3DBackBufferSurface);

	GET_SET_ACCESSOR(HWND,HWND);
	GET_SET_ACCESSOR(HWND,DlgHWND);
	GET_SET_ACCESSOR(HWND,FocusHWND);
	GET_SET_ACCESSOR(bool,WindowedState);
	GET_SET_ACCESSOR(bool,Display);
	GET_SET_ACCESSOR(float,FPS);
	GET_ACCESSOR(WCHAR*,WindowTitle);

	float GetBackBufferWidth(){ 
		return m_D3DState.m_D3DDeviceSettings.m_D3DPP.BackBufferWidth; 
	}
	float GetBackBufferHeight(){
		return m_D3DState.m_D3DDeviceSettings.m_D3DPP.BackBufferHeight; 
	}

	HRESULT OnCreateWindow(WCHAR* wcWindowTitle,HINSTANCE hInstance,HICON hIcon,int iX,int iY);
	bool OnCreateD3DDevice();
	bool IsDeviceLost();
	void SetOnInit(fpOnInit _fpOnInit);
	void SetLostDevice(fpOnLostDevice _fpOnLostDevice);
	void SetResetDevice(fpOnResetDevice _fpOnResetDevice);
	void SetUpdateFunc(fpUpdate _fpUpdate);
	void UpdateToDt();
	HRESULT OnDraw(fpRender render);
	void MainLoop(fpRender render);
	void Release(fpRelease _Release);
private:
	cTimeCounter* m_TimeCounter;

	void CheckDevice();
	bool GetUserDeviceSetting();
	cD3D m_D3DState;
	cD3DDeviceSettings m_OptimalDeviceSettings;

	fpOnInit OnInit;
	fpOnLostDevice OnLostDevice;
	fpOnResetDevice OnResetDevice;
	fpUpdate Update;
};
